package com.bright.cwduijie.duijie.service.impl;

import com.bright.cwduijie.common.config.BizThreadPoolExt;
import com.bright.cwduijie.duijie.enums.DataApi;
import com.bright.cwduijie.duijie.enums.SJJHBZ;
import com.bright.cwduijie.duijie.pojo.bo.ApiDataCollection;
import com.bright.cwduijie.duijie.pojo.command.SaveSendDataResultCommand;
import com.bright.cwduijie.duijie.pojo.command.SaveTaskIdCommand;
import com.bright.cwduijie.duijie.pojo.dto.CheckResultDto;
import com.bright.cwduijie.duijie.pojo.dto.SendDataReturnDto;
import com.bright.cwduijie.duijie.pojo.dto.SendFileDto;
import com.bright.cwduijie.duijie.pojo.po.DjFile;
import com.bright.cwduijie.duijie.pojo.query.DuijieQuery;
import com.bright.cwduijie.duijie.repository.DjFileRepository;
import com.bright.cwduijie.duijie.service.AbstractPerThousandApiService;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

/**
 * @Author hxj
 * @Date 2024/8/26 10:15
 * @Description 附件发送
 */

@Component
@RequiredArgsConstructor
@Slf4j
public class ApiSendFileServiceImpl extends AbstractPerThousandApiService<DjFile> {

    private final DjFileRepository repo;

    private final BizThreadPoolExt fileUploadPool;

    private final HttpClient httpClient;

    @Override
    protected void getData(ApiDataCollection apiDataCollection, DuijieQuery duijieQuery) {
        apiDataCollection.setDjFiles(getNeedDuijieData(duijieQuery));
    }

    @Override
    protected void checkDataValid(Map<String, CheckResultDto> checkResultDtoMap, ApiDataCollection apiDataCollection) {
        // 不进行校验
    }

    @Override
    public JpaSpecificationExecutor getJpaSpecificationExecutor() {
        return repo;
    }

    @Override
    public DataApi getDataApi() {
        // 这里随便给一个
        return DataApi.F01003;
    }

    @Override
    public Function<DjFile, Integer> getIdFunc() {
        return DjFile::getID;
    }

    @Override
    public Function<DjFile, String> getDataKeyFunc() {
        return DjFile::getDATA_KEY;
    }

    @Override
    public Function<ApiDataCollection, List<DjFile>> getDataFunc() {
        return ApiDataCollection::getDjFiles;
    }

    @Override
    protected DataApi getDeleteDataApi() {
        return null;
    }

    @Override
    public void sendData(ApiDataCollection apiDataCollection, DuijieQuery duijieQuery, String batchId) throws JsonProcessingException {
        //循环附件信息
        for (DjFile needDuiJieFile : apiDataCollection.getDjFiles()) {

            //异步进行数据推送
            CompletableFuture.runAsync(() -> {
                Thread.currentThread().setName(needDuiJieFile.getID() + "_" + needDuiJieFile.getDATA_KEY() + "_" + needDuiJieFile.getFILENAME());
                asyncSendFile(needDuiJieFile);
            }, fileUploadPool).exceptionally(throwable -> {
                throwable.printStackTrace();
                log.error("sendFiles 线程执行异常：", throwable);
                return null;
            });

        }
    }

    @Override
    public void sendDeleteData(DuijieQuery duijieQuery, String batchId) throws JsonProcessingException {
        List<DjFile> needDuiJieFiles = getNeedDeleteData(duijieQuery);

        Map<String, List<String>> methodFileList = new HashMap<>();
        Map<String, List<Integer>> methodIdList = new HashMap<>();

        for (DjFile needDuiJieFile : needDuiJieFiles) {

            String deleteUploadFileCode = needDuiJieFile.getDELETE_UPLOAD_FILE_CODE();

            //保存不同操作类型的所有附件的data_key
            List<String> dataKeys = methodFileList.getOrDefault(deleteUploadFileCode, new ArrayList<>(1));
            dataKeys.add(needDuiJieFile.getDATA_KEY());
            methodFileList.put(deleteUploadFileCode, dataKeys);


            //保存不同操作类型的所有附件的id
            List<Integer> ids = methodIdList.getOrDefault(deleteUploadFileCode, new ArrayList<>(1));
            ids.add(needDuiJieFile.getID());
            methodIdList.put(deleteUploadFileCode, ids);
        }

        //循环删除
        Map<String, Object> deleteMap = new HashMap<>();
        for (String temp : methodFileList.keySet()) {
            deleteMap.put("DATA_KEYS", methodFileList.get(temp));
            try {
                sendMapData(deleteMap, DataApi.of(temp), methodIdList.get(temp), batchId, null);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 异步发送附件
     * @param djFile 附件内容
     */
    private void asyncSendFile(DjFile djFile) {

        StringBuilder url = new StringBuilder("");

        SendFileDto sendFileDto = new SendFileDto();
        sendFileDto.setBusinessDataKey(djFile.getBUSINESS_DATA_KEY());
        sendFileDto.setTyshxydm(djFile.getTYSHXYDM());
        sendFileDto.setDataKey(djFile.getDATA_KEY());
        sendFileDto.setFileDateTime(LocalDateTime.now());

        //下载路径
        String name = djFile.getNAME();

        //原始文件
        String oldFileName = djFile.getFILENAME();

        url.setLength(0);
        url.append(djFile.getDOMAIN());
        url.append(name);



        HttpGet requestGet = new HttpGet(url.toString());
        HttpResponse responseResult = null;
        try {
            responseResult = httpClient.execute(requestGet);
        } catch (IOException e) {

            DataApi dataApi = Objects.requireNonNull(DataApi.of(djFile.getADD_UPLOAD_FILE_METHOD()));


            // 存到各张数据表的sjjhbz
            SaveSendDataResultCommand command = new SaveSendDataResultCommand();
            command.setDataApi(dataApi);
            command.setSjjhbz(SJJHBZ.ERROR.getValue());
            command.setTaskId(null);
            command.setIds(Collections.singletonList(djFile.getID()));
            duijieManager.saveSendDataResult(command);

            SaveTaskIdCommand saveTaskIdCommand = new SaveTaskIdCommand();
            saveTaskIdCommand.setTaskId(null);
            saveTaskIdCommand.setServiceCode(djFile.getADD_UPLOAD_FILE_CODE());
            saveTaskIdCommand.setType(dataApi.getDescription() + "-" + dataApi.getTableName());
            saveTaskIdCommand.setErrorMsg(e.getMessage());
            saveTaskIdCommand.setSjjhbz(SJJHBZ.ERROR.getValue());
            saveTaskIdCommand.setContent(djFile.getDOMAIN() + djFile.getNAME());
            duijieManager.saveAsyncTaskId(saveTaskIdCommand);
            log.error("网络请求异常： url: [{}]", url);
            return;
        }

        assert responseResult != null;
        //请求文件成功
        if (responseResult.getStatusLine().getStatusCode() == 200) {

            log.debug("文件下载成功 url: [{}]: ", url);

            try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

                //保存下载的文件
                responseResult.getEntity().writeTo(byteArrayOutputStream);
                byte[] bytes = byteArrayOutputStream.toByteArray();

                sendFileDto.setFile(bytes);
                sendFileDto.setFileName(oldFileName);
                byteArrayOutputStream.close();
                sendFile(sendFileDto, DataApi.of(djFile.getADD_UPLOAD_FILE_CODE()), Collections.singletonList(djFile.getID()));
//                //异步进行数据推送
//                CompletableFuture.runAsync(() -> {
//                    Thread.currentThread().setName(djFile.getID() + "_" + djFile.getDATA_KEY() + "_" + djFile.getFILENAME());
//
//                }, fileUploadPool).exceptionally(throwable -> {
//                    throwable.printStackTrace();
//                    log.error("sendFiles 线程执行异常：", throwable);
//                    return null;
//                });

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            try {
                log.error("下载文件失败 url : [{}] 错误信息: [{}]", url, EntityUtils.toString(responseResult.getEntity()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void sendFile(SendFileDto sendFileDto, DataApi dataApi, List<Integer> ids) {

        SendDataReturnDto accSetResult = null;
        String errorMsg = null;
        String dataStr = null;


        try {
            accSetResult = webExchangeService.sendFile(sendFileDto, dataApi.getServiceCode());
        } catch (Throwable throwable) {
            errorMsg = "接口发送时异常：" + throwable.getMessage();
            log.error("接口发送时异常：", throwable);
        }


        // 根据返回结果 回写异步任务id到表里
        int sjjhbz;
        String taskId;
        if (accSetResult != null && accSetResult.getIsSuccess()) {
            sjjhbz = SJJHBZ.EXECUTING.getValue();
            errorMsg = SJJHBZ.EXECUTING.getDescription();
            taskId = accSetResult.getTaskId();
        } else {
            sjjhbz = SJJHBZ.ERROR.getValue();
            // 如果出错 自己建一个taskId用于区分
            taskId = "error-" + System.currentTimeMillis();
            if (errorMsg == null && accSetResult != null) {
                errorMsg = "接口返回异常：" + accSetResult.getMessage();
            }
        }


        SaveTaskIdCommand saveTaskIdCommand = new SaveTaskIdCommand();
        saveTaskIdCommand.setTaskId(taskId);
        saveTaskIdCommand.setServiceCode(dataApi.getServiceCode());
        saveTaskIdCommand.setType(dataApi.getDescription() + "-" + dataApi.getTableName());
        saveTaskIdCommand.setErrorMsg(errorMsg);
        saveTaskIdCommand.setSjjhbz(sjjhbz);
        saveTaskIdCommand.setContent(dataStr);
        duijieManager.saveAsyncTaskId(saveTaskIdCommand);
        // 存到各张数据表的sjjhbz
        SaveSendDataResultCommand command = new SaveSendDataResultCommand();
        command.setDataApi(dataApi);
        command.setSjjhbz(sjjhbz);
        command.setTaskId(taskId);
        command.setIds(ids);
        duijieManager.saveSendDataResult(command);
    }
}
